#ifndef AVALON_MASK_HPP
#define AVALON_MASK_HPP
#include "Avalon/Base/Base.hpp"

namespace Avalon {

  /*! \struct BaseMask
   *  \brief Base class of a Mask.
   */
  struct BaseMask {};

  /*! \struct Mask
   *  \brief Boilerplate code for a set of identifiers.
   */
  template<typename T, unsigned int S, typename K = unsigned int>
  struct Mask : BaseMask {
    public:

      //! Defines the instantiated type of this template.
      typedef Mask<T, S, K> MaskType;

      //! The type used to represent an identifier.
      typedef K ValueType;

      //! The total number of of identifiers.
      static const unsigned int SIZE = S;

      //! Represents the set of no identifiers.
      static const T NONE;

      //! Represents the set of all identifiers.
      static const T ALL;

      //! Creates the NONE Mask.
      Mask()
          : m_value(0) {}

      //! Returns a Mask of identifiers excluded by <i>this</i> Mask.
      T operator ~() const {
        return T(~m_value & ALL_VALUE);
      }

      //! Compares this Mask with another for equality.
      /*!
        \param rhs The right hand side of the equality.
        \return <code>true</code> iff the two Masks are equal.
      */
      bool operator ==(T rhs) const {
        return m_value == rhs.m_value;
      }

      //! Compares this Mask with another for inequality.
      /*!
        \param rhs The right hand side of the inequality.
        \return <code>true</code> iff the two Masks are not equal.
      */
      bool operator !=(T rhs) const {
        return m_value != rhs.m_value;
      }

      //! Less than operator.
      /*!
        \param rhs The right hand side of the operation.
        \return <code>true</code> iff this is less than <i>rhs</i>.
      */
      bool operator <(T rhs) const {
        return m_value < rhs.m_value;
      }

      //! Returns a Mask composed <i>this</i> and another Mask.
      /*!
        \param rhs The Mask to compose.
        \return A Mask containing the identifiers of <i>this</i> and
                <i>rhs</i>.
      */
      T operator |(T rhs) const {
        return T(m_value | rhs.m_value);
      }

      //! Adds identifiers to <i>this</i> Mask.
      /*!
        \param rhs The Mask to add from.
        \return <i>this</i>.
      */
      T& operator |=(T rhs) {
        m_value |= rhs.m_value;
        return reinterpret_cast<T&>(*this);
      }

      //! Returns a Mask with the identifiers in common with another Mask.
      /*!
        \param rhs The Mask to check for common identifiers.
        \return A Mask containing the identifiers in common with <i>this</i>
                and <i>rhs</i>.
      */
      T operator &(T rhs) const {
        return T(m_value & rhs.m_value);
      }

      //! Removes all identifiers that are not in common with another Mask.
      /*!
        \param rhs The Mask to compared identifiers with.
        \return <i>this</i>
      */
      T& operator &=(T rhs) {
        m_value &= rhs.m_value; return reinterpret_cast<T&>(*this);
      }

      //! Tests if this Mask contains at least one identifier.
      operator bool() const {
        return m_value != 0;
      }

      //! Returns the bitwise value of this Mask.
      ValueType GetValue() const {
        return m_value;
      }

      //! Returns the index of this Mask.
      ValueType GetIndex() const {
        return GetIndexHelper(m_value);
      }

    protected:

      //! Declares a new identifier.
      /*!
        \return An instance of the newly declared identifier.
      */
      static T DeclareNewIdentifier() {
        ValueType value = m_nextIdentifierValue;
        m_nextIdentifierValue <<= 1;
        T identifier(value);
        assert(identifier.m_value == value);
        return identifier;
      }

      //! Constructs a Mask.
      /*!
        \param value The bitwise value.
      */
      Mask(ValueType value)
          : m_value(value >= 0 && value <= ALL_VALUE ? value : 0) {}

    private:
      static ValueType m_nextIdentifierValue;
      static const ValueType VALIDATE_SIZE = 1 << SIZE;
      static const ValueType ALL_VALUE = ((1 << S) - 1);
      ValueType m_value;

      static ValueType GetIndexHelper(ValueType value) {
        switch(value) {
          case 0:
            return SIZE;
          case 1 << 0:
            return 0;
          case 1 << 1:
            return 1;
          case 1 << 2:
            return 2;
          case 1 << 3:
            return 3;
          case 1 << 4:
            return 4;
          case 1 << 5:
            return 5;
          case 1 << 6:
            return 6;
          case 1 << 7:
            return 7;
        }
        value >>= 7;
        ValueType index = GetIndexHelper(value);
        if(index == SIZE) {
          return SIZE;
        }
        return 8 + index;
      }
  };

  //! Defines the next identifier value.
  template<typename T, unsigned int S, typename K>
  typename Mask<T, S, K>::ValueType Mask<T, S, K>::m_nextIdentifierValue = 1;

  //! Defines the empty Mask.
  template<typename T, unsigned int S, typename K>
  const T Mask<T, S, K>::NONE(0);

  //! Defines the full Mask.
  template<typename T, unsigned int S, typename K>
  const T Mask<T, S, K>::ALL(Mask<T, S, K>::ALL_VALUE);
}

#endif // AVALON_MASK_HPP
